﻿using System;
using System.Collections.Generic;
using System.Text;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraEditors.Repository;
using System.Windows.Forms;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraEditors;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
using System.Drawing;
using DevExpress.XtraEditors.Controls;

namespace WmsApp.Style
{
    /// <summary>
    /// 表格cell数据拷贝器
    /// </summary>
    public class GridCellCopier
    {
        #region 私有变量
        //bool setBrushPosition = false;
        bool brushIsLeft = true;
        Rectangle MouseRect = Rectangle.Empty;
        int FinalFocusHandle = -1;
        bool MouseIsDown = false;
        RepositoryItemButtonEdit repEdit;
        GridView gv;
        GridCellCopierItem item;
        ContextMenu menu = null;
        int BrushButtonIndex = -1;
        const int ImageWidth = 9;
        const int MouseWidth = 16;
        bool HasButtonEdit = true;
        #endregion

        /// <summary>
        /// 构造器1
        /// </summary>
        /// <param name="gv">GridView</param>
        /// <param name="item">GridCellCopierItem对象</param>
        public GridCellCopier(GridView gv, GridCellCopierItem item)
        {
            this.gv = gv;
            this.item = item;

            if (item.GC.ColumnEdit != null)
            {
                if (item.GC.ColumnEdit is RepositoryItemButtonEdit)
                {
                    repEdit = item.GC.ColumnEdit as RepositoryItemButtonEdit;
                }
                else if (item.GC.ColumnEdit is RepositoryItemTextEdit)//如CheckBox，TextBox之类
                {
                    repEdit = new RepositoryItemButtonEdit();
                    repEdit.Buttons.Clear();
                    item.GC.ColumnEdit = repEdit;
                }
                else if (item.GC.ColumnEdit is RepositoryItemCheckEdit)
                {
                    return;
                }
                else
                {
                    HasButtonEdit = false;
                    RegEvents();
                }
            }
            else
            {
                repEdit = new RepositoryItemButtonEdit();
                repEdit.Buttons.Clear();
                item.GC.ColumnEdit = repEdit;
            }

            if (HasButtonEdit)
            {
                repEdit.Mask.UseMaskAsDisplayFormat = true;
                if (String.IsNullOrEmpty(repEdit.Mask.EditMask))
                {
                    if (String.IsNullOrEmpty(item.Format))
                    {
                        repEdit.Mask.EditMask = item.GC.DisplayFormat.FormatString;
                    }
                    else
                    {
                        repEdit.Mask.EditMask = item.Format;
                    }
                }

                RegEvents();

                if (!this.gv.GridControl.RepositoryItems.Contains(repEdit))
                {
                    this.gv.GridControl.RepositoryItems.AddRange(new RepositoryItem[] { repEdit });
                }

                EditorButton brushButton = new DevExpress.XtraEditors.Controls.EditorButton(
               DevExpress.XtraEditors.Controls.ButtonPredefines.Glyph,
               "", ImageWidth, true, true, true, DevExpress.Utils.HorzAlignment.Near,null);

                brushButton.ToolTip = "按住左键拖拉可以复制单元格,也可以点击右键复制到整列.";

                BrushButtonIndex = this.repEdit.Buttons.Add(brushButton);
                this.repEdit.Name = "repEdit";
                this.repEdit.Buttons[BrushButtonIndex].Visible = false;
            }
        }

        /// <summary>
        /// 构造器2
        /// </summary>
        /// <param name="gv">GridView</param>
        /// <param name="item">GridCellCopierItem对象</param>
        /// <param name="brushIsLeft">格式刷按钮是否放在前面</param>
        public GridCellCopier(GridView gv, GridCellCopierItem item, bool brushIsLeft)
            : this(gv, item)
        {
            if (HasButtonEdit)
            {
                //this.setBrushPosition = true;
                this.brushIsLeft = brushIsLeft;
                this.repEdit.Buttons[BrushButtonIndex].IsLeft = brushIsLeft;
            }
        }

        private void RegEvents()
        {

            item.GC.ColumnEdit.ParseEditValue += new ConvertEditValueEventHandler(repEdit_ParseEditValue);
            item.GC.ColumnEdit.MouseDown += new MouseEventHandler(repEdit_MouseDown);
            item.GC.ColumnEdit.MouseMove += new MouseEventHandler(repEdit_MouseMove);
            item.GC.ColumnEdit.MouseUp += new MouseEventHandler(repEdit_MouseUp);
            item.GC.ColumnEdit.MouseLeave += new EventHandler(repEdit_MouseLeave);
        }

        private void repEdit_MouseLeave(object sender, EventArgs e)
        {
            if (HasButtonEdit)
            {
                this.GetEditorButton(sender).Visible = false;
            }
        }

        private void repEdit_ParseEditValue(object sender, ConvertEditValueEventArgs e)
        {
            #region 针对格式的处理，暂时不用
            //this.repEdit.EditFormat.FormatString = this.item.GC.DisplayFormat.FormatString;
            //this.repEdit.EditFormat.FormatType = this.item.GC.DisplayFormat.FormatType;

            //this.repEdit.DisplayFormat.FormatString = this.item.GC.DisplayFormat.FormatString;
            //this.repEdit.DisplayFormat.FormatType = this.item.GC.DisplayFormat.FormatType;

            //if (!setBrushPosition)
            //{
            //    if (this.item.GC.DisplayFormat.FormatType == DevExpress.Utils.FormatType.Numeric)
            //    {
            //        this.brushIsLeft = true;
            //        this.GetEditorButton(sender).IsLeft = this.brushIsLeft;
            //    }
            //    else
            //    {
            //        this.brushIsLeft = false;
            //        this.GetEditorButton(sender).IsLeft = this.brushIsLeft;
            //    }
            //}
            #endregion
        }

        private void repEdit_MouseDown(object sender, MouseEventArgs e)
        {
            TextEdit textEdit = GetTextEdit(sender);
            if ((brushIsLeft && e.X <= MouseWidth) || (!brushIsLeft && textEdit.Width - e.X <= MouseWidth))
            {
                if (e.Button == MouseButtons.Left)
                {
                    FinalFocusHandle = gv.FocusedRowHandle;
                    Point loc = new Point(0, 0);
                    MouseIsDown = true;
                    DrawStart(GetTextEdit(sender), loc);
                    Cursor.Current = Cursors.Cross;
                }
                else if (e.Button == MouseButtons.Right)
                {
                    menu = new ContextMenu();
                    MenuItem mi = new MenuItem();
                    mi.Text = "复制到整列";
                    mi.Click += delegate(object sender2, EventArgs e2)
                    {
                        try
                        {
                            gv.SetRowCellValue(gv.FocusedRowHandle, gv.FocusedColumn, GetTextEdit(sender).EditValue);

                            object obj = gv.GetFocusedValue();
                            for (int idx = 0; idx < gv.RowCount; idx++)
                            {
                                if (idx != gv.FocusedRowHandle)
                                {
                                    gv.SetRowCellValue(idx, gv.FocusedColumn, obj);
                                }
                            }
                        }
                        catch { }
                    };

                    menu.MenuItems.Add(mi);
                    menu.Show(this.GetTextEdit(sender), e.Location);
                }
            }
        }

        private EditorButton GetEditorButton(object sender)
        {
            TextEdit te = GetTextEdit(sender);
            if (te is ButtonEdit)
            {
                return (te as ButtonEdit).Properties.Buttons[BrushButtonIndex];
            }
            return null;
        }

        private TextEdit GetTextEdit(object sender)
        {
            return sender as TextEdit;
        }

        private void repEdit_MouseMove(object sender, MouseEventArgs e)
        {
            TextEdit textEdit = GetTextEdit(sender);
            if (e.Button == MouseButtons.None)
            {
                if ((brushIsLeft && e.X <= MouseWidth) || (!brushIsLeft && textEdit.Width - e.X <= MouseWidth))
                {
                    SetCursor(false, sender);
                }
                else
                {
                    SetCursor(true, sender);
                }
            }
            else
            {
                if (e.Button == MouseButtons.Left)
                {
                    if (MouseIsDown)
                    {
                        Point loc = new Point();
                        loc.X = textEdit.Width;
                        loc.Y = e.Location.Y;
                        ResizeToRectangle(textEdit, loc);
                    }
                }
                else if (e.Button == MouseButtons.Right)
                {
                    if ((brushIsLeft && e.X <= MouseWidth) || (!brushIsLeft && textEdit.Width - e.X <= MouseWidth))
                    {
                        SetCursor(false, sender);
                    }
                    else
                    {
                        SetCursor(true, sender);
                    }
                }
            }
        }

        private bool PointIsInCell(Point p, out GridHitInfo info)
        {
            info = this.gv.CalcHitInfo(p);
            if (info != null && info.RowHandle >= 0)
            {
                return true;
            }
            return false;
        }


        private void ResizeToRectangle(TextEdit textEdit, Point p)
        {
            int x = textEdit.Left + p.X;
            int y = textEdit.Top + p.Y;
            GridHitInfo info;
            if (PointIsInCell(new Point(x, y), out info))
            {
                DrawRectangle(textEdit);

                MouseRect.Width = p.X - MouseRect.Left;
                MouseRect.Height = p.Y - MouseRect.Top;

                if (info.RowHandle > gv.FocusedRowHandle)
                {
                    MouseRect.Height = (info.RowHandle - gv.FocusedRowHandle + 1) * (textEdit.Height + 3);
                }
                else
                {
                    MouseRect.Height = -(gv.FocusedRowHandle - info.RowHandle) * (textEdit.Height + 3);
                }

                DrawRectangle(textEdit);
                FinalFocusHandle = info.RowHandle;
            }
        }

        private void DrawRectangle(TextEdit textEdit)
        {
            Rectangle rect = textEdit.RectangleToScreen(MouseRect);
            ControlPaint.FillReversibleRectangle(rect, Color.Blue);
        }

        private void SetCursor(bool isDefault, object obj)
        {
            TextEdit textEdit = this.GetTextEdit(obj);
            if (isDefault)
            {
                Cursor.Current = Cursors.Default;

                EditorButton eb = GetEditorButton(obj);
                if (eb != null)
                {
                    eb.Visible = false;
                }
            }
            else
            {

                Cursor.Current = Cursors.Cross;

                EditorButton eb = GetEditorButton(obj);
                if (eb != null)
                {
                    eb.Visible = true;
                }

                if (this.gv.GetFocusedValue() == textEdit.EditValue)
                {
                    textEdit.DoValidate();
                    //this.gv.SetFocusedValue(this.textEdit.EditValue);
                }

            }
        }

        private void DrawStart(TextEdit textEdit, Point startPoint)
        {
            int topRow = this.gv.TopRowIndex;
            int focusRow = this.gv.FocusedRowHandle;

            int height = focusRow - topRow;
            int recTop = (textEdit.Height + 1) * height;

            textEdit.Capture = true;
            Cursor.Clip = this.gv.GridControl.RectangleToScreen(new Rectangle(textEdit.Left, -1 * recTop, textEdit.Width,
                2000));
            MouseRect = new Rectangle(startPoint.X, startPoint.Y, 0, 0);
        }

        private void repEdit_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                SetCursor(true, sender);
                this.GetTextEdit(sender).Capture = false;
                Cursor.Clip = Rectangle.Empty;

                //DrawRectangle(this.GetTextEdit(sender));
                MouseRect = Rectangle.Empty;
                if (MouseIsDown)
                {
                    if (this.FinalFocusHandle > gv.FocusedRowHandle)
                    {
                        for (int idx = this.FinalFocusHandle; idx > gv.FocusedRowHandle; idx--)
                        {
                            gv.SetRowCellValue(idx, gv.FocusedColumn, (sender as TextEdit).EditValue);
                        }
                    }
                    else if (this.FinalFocusHandle < gv.FocusedRowHandle)
                    {
                        for (int idx = this.FinalFocusHandle; idx < gv.FocusedRowHandle; idx++)
                        {
                            gv.SetRowCellValue(idx, gv.FocusedColumn, (sender as TextEdit).EditValue);
                        }
                    }
                }
                FinalFocusHandle = gv.FocusedRowHandle;
                MouseIsDown = false;
                ControlPaint.DrawReversibleFrame(Rectangle.Empty, Color.Blue, FrameStyle.Thick);
            }
        }
    }

    public class GridCellCopierItem
    {
        GridView gv;
        GridColumn gc;
        string format;
        Type type;
        public GridCellCopierItem(GridColumn gc, string format, Type type)
        {
            this.gc = gc;
            this.format = format;
            this.type = type;
        }

        public GridCellCopierItem(string columnName, GridView gv, string format, Type type)
        {
            this.gv = gv;
            this.gc = gv.Columns[columnName];
            this.format = format;
            this.type = type;
        }

        public GridColumn GC
        {
            get { return gc; }
        }

        public string Format
        {
            get { return this.format; }
        }

        public Type DataType
        {
            get { return type; }
        }
    }
}
